package com.sjgs.gis.fsrest.handler;

import com.sjgs.common.utils.DirUtils;
import com.sjgs.gis.common.FileSystemFactory;
import com.sjgs.gis.domain.enumeration.DataFileStatus;
import com.sjgs.gis.service.TileSetService;
import com.sjgs.gis.service.DataFileService;
import com.sjgs.gis.errors.BadRequestAlertException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourceRegion;
import org.springframework.http.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.Exceptions;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static java.lang.Math.min;

@Controller
public class FileSystemDownloadHandler {

    private static final Log logger = LogFactory.getLog(FileSystemDownloadHandler.class);

    @Value("${filesystem.rootDir:/data}")
    private String rootDir;

    @Autowired
    TileSetService tileSetService;

    private final DataFileService dfservice;

    public FileSystemDownloadHandler(DataFileService service) {
        this.dfservice = service;
    }


    /**
     * 测试http下载接口
     *
     * @param request
     * @return
     */
    //@GetMapping(value = "/download-service/file/{fkey}")
    public Mono<ServerResponse> getFile(ServerRequest request) {
        String fkey = request.pathVariable("fkey");
        HttpHeaders requestHeaders = request.headers().asHttpHeaders();
        return dfservice.findByFkeyAndStatus(fkey, DataFileStatus.RSYNC_FINISHED.ordinal())
                .flatMap(df -> {
                    //TODO 文件不存在建立->grpcresource代理读取数据
                    Mono<Resource> resourceMono = FileSystemFactory.instance().getResource(df);
                    Mono<ResourceRegion> resourceRegionMono = FileSystemFactory.instance()
                            .getResourceRegion(df, resourceMono, requestHeaders);
                    return resourceRegionMono
                            .flatMap(resourceRegion -> {
                                return ServerResponse
                                        .status(HttpStatus.PARTIAL_CONTENT)
                                        .contentLength(resourceRegion.getCount())
                                        .headers(headers -> headers.setCacheControl(CacheControl.noCache()))
                                        .body(resourceRegionMono, ResourceRegion.class);
                            })
                            .doOnError(throwable -> {
                                throw Exceptions.propagate(throwable);
                            });
                })
                .switchIfEmpty(Mono.error(new BadRequestAlertException("Not Found", "DataFile", fkey)));
    }

    /**
     * 测试http块下载
     *
     * @param request
     * @return
     */
    //@GetMapping(value = "/download-service/chunk/{fkey}/index/{index}")
    public Mono<ServerResponse> getChunk(ServerRequest request) {
        String fkey = request.pathVariable("fkey");
        String index = request.pathVariable("index");
        return dfservice.findByFkeyAndStatusLessThanEqual(fkey, DataFileStatus.CHUNK_FINISHED.ordinal())
                .flatMap(df -> {
                    Path chunkpath = DirUtils.getChunkPath(rootDir, df.getDir(), fkey, Long.valueOf(index));
                    if (Files.notExists(chunkpath)) {
                        logger.warn("Not Found Chunk for " + fkey + ":" + index);
                        return ServerResponse.notFound().build();
                    } else {
                        FileSystemResource resource = new FileSystemResource(chunkpath);
                        Long count = 0L;
                        try {
                            count = resource.contentLength();
                        } catch (IOException e) {
                            logger.warn("Not Found Chunk for " + fkey + ":" + index);
                            throw new BadRequestAlertException("Not Found", "Chunk", fkey + ":" + index);
                        }
                        Mono<ResourceRegion> resourceRegionMono = Mono.just(new ResourceRegion(resource, 0, count));
                        return resourceRegionMono
                                .flatMap(resourceRegion -> {
                                    return ServerResponse
                                            .status(HttpStatus.OK)
                                            .contentLength(resourceRegion.getCount())
                                            .headers(headers -> headers.setCacheControl(CacheControl.noCache()))
                                            .body(resourceRegionMono, ResourceRegion.class);
                                })
                                .doOnError(throwable -> {
                                    throw Exceptions.propagate(throwable);
                                });
                    }
                }).switchIfEmpty(Mono.error(new BadRequestAlertException("Not Found", "Chunk", fkey + ":" + index)));
    }

    /**
     * 测试http瓦片
     *
     * @param request
     * @return
     */
    public Mono<ServerResponse> getTileSet(ServerRequest request) {
        String id = request.pathVariable("id");
        System.out.println(id);
        //TODO return layer.json or tileset.json
        return ServerResponse.notFound().build();
    }

    /**
     * 测试http瓦片
     *
     * @param request
     * @return
     */
    public Mono<ServerResponse> getTile(ServerRequest request) {
        String id = request.pathVariable("id");
        System.out.println(id);
        String path = request.path();
        System.out.println(path);
        if (path.endsWith(id)) {
            return getTileSet(request);
        } else {
            //子路径
            if (path.endsWith("layer.json") || path.endsWith("tileset.json")) {
                System.out.println(1);
            } else if (path.endsWith("scenes.json")) {
                System.out.println(2);
            } else {
                System.out.println(3);
            }
        }
        return ServerResponse.notFound().build();
    }
}
